// HTMLParser Library $Name: v1_6 $ - A java-based parser for HTML
// http://sourceforge.org/projects/htmlparser
// Copyright (C) 2004 Derrick Oswald
//
// Revision Control Information
//
// $Source: /cvsroot/htmlparser/htmlparser/src/org/htmlparser/sax/Attributes.java,v $
// $Author: derrickoswald $
// $Date: 2004/07/14 01:58:02 $
// $Revision: 1.1 $
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation; either
// version 2.1 of the License, or (at your option) any later version.
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
//

package org.htmlparser.sax;

import org.htmlparser.Attribute;
import org.htmlparser.Tag;
import org.xml.sax.helpers.NamespaceSupport;

import java.util.Vector;

/**
 * Provides access to the tag attributes.
 */
public class Attributes implements org.xml.sax.Attributes {
    /**
     * The tag from which attributes are exposed.
     */
    protected Tag mTag;

    /**
     * The utility class that converts namespaces.
     */
    protected NamespaceSupport mSupport;

    /**
     * Elements of the qname. Allocated once for all uses of {@link #mSupport}.
     */
    protected String[] mParts;

    /**
     * Create an attibute access object.
     *
     * @param tag     The tag to expose.
     * @param support The namespace converter.
     * @param parts   The elements of the qualified name.
     */
    public Attributes(Tag tag, NamespaceSupport support, String[] parts) {
        mTag = tag;
        mSupport = support;
        mParts = parts;
    }

    // //////////////////////////////////////////////////////////////////
    // Indexed access.
    // //////////////////////////////////////////////////////////////////

    /**
     * Return the number of attributes in the list.
     * <p/>
     * <p>
     * Once you know the number of attributes, you can iterate through the list.
     * </p>
     *
     * @return The number of attributes in the list.
     * @see #getURI(int)
     * @see #getLocalName(int)
     * @see #getQName(int)
     * @see #getType(int)
     * @see #getValue(int)
     */
    public int getLength() {
        return (mTag.getAttributesEx().size() - 1);
    }

    /**
     * Look up an attribute's Namespace URI by index.
     *
     * @param index The attribute index (zero-based).
     * @return The Namespace URI, or the empty string if none is available, or
     *         null if the index is out of range.
     * @see #getLength
     */
    public String getURI(int index) {
        mSupport.processName(getQName(index), mParts, true);
        return (mParts[0]);
    }

    /**
     * Look up an attribute's local name by index.
     *
     * @param index The attribute index (zero-based).
     * @return The local name, or the empty string if Namespace processing is
     *         not being performed, or null if the index is out of range.
     * @see #getLength
     */
    public String getLocalName(int index) {
        mSupport.processName(getQName(index), mParts, true);
        return (mParts[1]);
    }

    /**
     * Look up an attribute's XML qualified (prefixed) name by index.
     *
     * @param index The attribute index (zero-based).
     * @return The XML qualified name, or the empty string if none is available,
     *         or null if the index is out of range.
     * @see #getLength
     */
    public String getQName(int index) {
        Attribute attribute;
        String ret;

        attribute = (Attribute) (mTag.getAttributesEx().elementAt(index + 1));
        if (attribute.isWhitespace())
            ret = "#text";
        else
            ret = attribute.getName();

        return (ret);
    }

    /**
     * Look up an attribute's type by index.
     * <p/>
     * <p>
     * The attribute type is one of the strings "CDATA", "ID", "IDREF",
     * "IDREFS", "NMTOKEN", "NMTOKENS", "ENTITY", "ENTITIES", or "NOTATION"
     * (always in upper case).
     * </p>
     * <p/>
     * <p>
     * If the parser has not read a declaration for the attribute, or if the
     * parser does not report attribute types, then it must return the value
     * "CDATA" as stated in the XML 1.0 Recommendation (clause 3.3.3,
     * "Attribute-Value Normalization").
     * </p>
     * <p/>
     * <p>
     * For an enumerated attribute that is not a notation, the parser will
     * report the type as "NMTOKEN".
     * </p>
     *
     * @param index The attribute index (zero-based).
     * @return The attribute's type as a string, or null if the index is out of
     *         range.
     * @see #getLength
     */
    public String getType(int index) {
        return ("CDATA");
    }

    /**
     * Look up an attribute's value by index.
     * <p/>
     * <p>
     * If the attribute value is a list of tokens (IDREFS, ENTITIES, or
     * NMTOKENS), the tokens will be concatenated into a single string with each
     * token separated by a single space.
     * </p>
     *
     * @param index The attribute index (zero-based).
     * @return The attribute's value as a string, or null if the index is out of
     *         range.
     * @see #getLength
     */
    public String getValue(int index) {
        Attribute attribute;
        String ret;

        attribute = (Attribute) (mTag.getAttributesEx().elementAt(index + 1));
        ret = attribute.getValue();
        if (null == ret) ret = "";

        return (ret);
    }

    // //////////////////////////////////////////////////////////////////
    // Name-based query.
    // //////////////////////////////////////////////////////////////////

    /**
     * Look up the index of an attribute by Namespace name.
     *
     * @param uri       The Namespace URI, or the empty string if the name has no
     *                  Namespace URI.
     * @param localName The attribute's local name.
     * @return The index of the attribute, or -1 if it does not appear in the
     *         list.
     */
    public int getIndex(String uri, String localName) {
        Vector attributes;
        int size;
        Attribute attribute;
        String string;
        int ret;

        ret = -1;

        attributes = mTag.getAttributesEx();
        if (null != attributes) {
            size = attributes.size();
            for (int i = 1; i < size; i++) {
                attribute = (Attribute) attributes.elementAt(i);
                string = attribute.getName();
                if (null != string) // not whitespace
                {
                    mSupport.processName(string, mParts, true);
                    if (uri.equals(mParts[0]) & localName.equalsIgnoreCase(mParts[1])) {
                        ret = i;
                        i = size; // exit fast
                    }
                }
            }
        }

        return (ret);
    }

    /**
     * Look up the index of an attribute by XML qualified (prefixed) name.
     *
     * @param qName The qualified (prefixed) name.
     * @return The index of the attribute, or -1 if it does not appear in the
     *         list.
     */
    public int getIndex(String qName) {
        mSupport.processName(qName, mParts, true);
        return (getIndex(mParts[0], mParts[1]));
    }

    /**
     * Look up an attribute's type by Namespace name.
     * <p/>
     * <p>
     * See {@link #getType(int) getType(int)} for a description of the possible
     * types.
     * </p>
     *
     * @param uri       The Namespace URI, or the empty String if the name has no
     *                  Namespace URI.
     * @param localName The local name of the attribute.
     * @return The attribute type as a string, or null if the attribute is not
     *         in the list or if Namespace processing is not being performed.
     */
    public String getType(String uri, String localName) {
        return (null);
    }

    /**
     * Look up an attribute's type by XML qualified (prefixed) name.
     * <p/>
     * <p>
     * See {@link #getType(int) getType(int)} for a description of the possible
     * types.
     * </p>
     *
     * @param qName The XML qualified name.
     * @return The attribute type as a string, or null if the attribute is not
     *         in the list or if qualified names are not available.
     */
    public String getType(String qName) {
        return (null);
    }

    /**
     * Look up an attribute's value by Namespace name.
     * <p/>
     * <p>
     * See {@link #getValue(int) getValue(int)} for a description of the
     * possible values.
     * </p>
     *
     * @param uri       The Namespace URI, or the empty String if the name has no
     *                  Namespace URI.
     * @param localName The local name of the attribute.
     * @return The attribute value as a string, or null if the attribute is not
     *         in the list.
     */
    public String getValue(String uri, String localName) {
        return (mTag.getAttribute(localName));
    }

    /**
     * Look up an attribute's value by XML qualified (prefixed) name.
     * <p/>
     * <p>
     * See {@link #getValue(int) getValue(int)} for a description of the
     * possible values.
     * </p>
     *
     * @param qName The XML qualified name.
     * @return The attribute value as a string, or null if the attribute is not
     *         in the list or if qualified names are not available.
     */
    public String getValue(String qName) {
        mSupport.processName(qName, mParts, true);
        return (getValue(mParts[0], mParts[1]));
    }
}
